/*
 */

#ifndef _DATABASE_H
#define _DATABASE_H

#include <string>
#include "Threading/Queue.h"
#include "CallBack.h"

using namespace std;
class QueryResult;
class QueryThread;
class Database;

struct DatabaseConnection
{
	FastMutex Busy;
	String		last_sql;
};

struct SERVER_DECL AsyncQueryResult
{
	QueryResult * result;
	char * query;
};

class SERVER_DECL AsyncQuery
{
	friend class Database;
	SQLCallbackBase * func;
	vector<AsyncQueryResult> queries;
	Database * db;
public:
	AsyncQuery(SQLCallbackBase * f) : func(f) {}
	~AsyncQuery();
	void AddQuery(const char * format, ...);
	void Perform();
	WGSERVER_INLINE void SetDB(Database * dbb) { db = dbb; }
};

class SERVER_DECL QueryBuffer
{
	vector<char*> queries;
public:
	friend class Database;
	virtual ~QueryBuffer(void);
	void AddQuery( const char * format, ... );
	void AddQueryNA( const char * str );
	void AddQueryStr(const string& str);
};

class SERVER_DECL Database : public CThread
{
	friend class QueryThread;
	friend class AsyncQuery;
public:
	Database();
	virtual ~Database();

	/************************************************************************/
	/* Thread Stuff                                                         */
	/************************************************************************/
	bool run();

	/************************************************************************/
	/* Virtual Functions                                                    */
	/************************************************************************/
	virtual bool Initialize(const char* Hostname, unsigned int port,
		const char* Username, const char* Password, const char* DatabaseName,
		uint32 ConnectionCount, uint32 BufferSize) = 0;
	
	virtual void Shutdown() = 0;

	virtual QueryResult* Query(const char* QueryString, ...);
	virtual QueryResult* QueryNA(const char* QueryString);
	virtual QueryResult * FQuery(DatabaseConnection * con,const char * QueryString, ...);
	virtual QueryResult * FQueryNA( DatabaseConnection * con,const char * QueryString);
	virtual void FWaitExecuteNA(DatabaseConnection * con,const char * QueryString);
	virtual void FWaitExecute(DatabaseConnection * con,const char * QueryString, ...);
	virtual bool WaitExecute(const char* QueryString, ...);//Wait For Request Completion
	virtual bool WaitExecuteNA(const char* QueryString);//Wait For Request Completion
	
	virtual bool Execute(const char* QueryString, ...);
	virtual bool ExecuteNA(const char* QueryString);

	//返回影响的记录数量 如果出错返回 -1;
	virtual QueryResult* QueryAffected(const char* QueryString, ...);
	virtual QueryResult* QueryAffectedNA(const char* QueryString);
	virtual QueryResult * FQueryAffected(DatabaseConnection * con,const char * QueryString, ...);
	virtual QueryResult * FQueryAffectedNA( DatabaseConnection * con,const char * QueryString);
	virtual void FWaitExecuteAffectedNA(DatabaseConnection * con,const char * QueryString);
	virtual void FWaitExecuteAffected(DatabaseConnection * con,const char * QueryString, ...);
	virtual int WaitExecuteAffected(const char* QueryString, ...);//Wait For Request Completion
	virtual int WaitExecuteAffectedNA(const char* QueryString);//Wait For Request Completion




	virtual	uint32	QueryUInt32(const char * QueryString,...);
	virtual	int32	QueryInt32(const char * QueryString,...);
	virtual	float	QueryFloat(const char * QueryString,...);
	
	// Initialized on load: Database::Database() : CThread()
	bool ThreadRunning;

	WGSERVER_INLINE const string& GetHostName() { return mHostname; }
	WGSERVER_INLINE const string& GetDatabaseName() { return mDatabaseName; }
	WGSERVER_INLINE const uint32 GetQueueSize() { return queries_queue.get_size(); }

	virtual string EscapeString(const string & Escape) = 0;
	virtual void EscapeLongString(const char * str, uint32 len, stringstream& out) = 0;
	virtual string EscapeString(const char * esc, DatabaseConnection * con) = 0;
	
	void QueueAsyncQuery(AsyncQuery * query);
	void EndThreads();
	
	void thread_proc_query();
	void FreeQueryResult(QueryResult * p);

	DatabaseConnection * GetFreeConnection();
	int	GetFreeCount(void);
	int	GetConnectionCount(void)	{	return mConnectionCount;	}

	void PerformQueryBuffer(QueryBuffer * b, DatabaseConnection * ccon);
	void AddQueryBuffer(QueryBuffer * b);

	static Database * CreateDatabaseInterface(uint32 uType=1);
	static void CleanupLibs();

	virtual bool SupportsReplaceInto() = 0;
	virtual bool SupportsTableLocking() = 0;

	virtual const string & getHostName(void)	{	return mHostname;	}
	virtual const string & getDatabase(void)	{	return mDatabaseName;	}
	virtual const string & getUserName(void)	{	return mUsername;	}
	virtual const string & getPassword(void)	{	return mPassword;	}
	virtual const uint16	getPort(void)		{	return mPort;		}

	//得到被影响的rows
	uint32 GetAffectedRows(void)	{	return mAffectedRows;	}
protected:

	// spawn threads and shizzle
	void _Initialize();

	virtual void _BeginTransaction(DatabaseConnection * conn) = 0;
	virtual void _EndTransaction(DatabaseConnection * conn) = 0;

	// actual query function
	virtual bool _SendQuery(DatabaseConnection *con, const char* Sql, bool Self) = 0;
	virtual QueryResult * _StoreQueryResult(DatabaseConnection * con) = 0;
	// affected rows 
	virtual uint32 _AffectedRows(DatabaseConnection *con);

	////////////////////////////////
	FQueue<QueryBuffer*> query_buffer;

	////////////////////////////////
	FQueue<char*> queries_queue;
	DatabaseConnection ** Connections;
	
	uint32 _counter;
	///////////////////////////////

	int32 mConnectionCount;

	// For reconnecting a broken connection
	string mHostname;
	string mUsername;
	string mPassword;
	string mDatabaseName;
	uint32 mPort;

	//SQL语句影响的记录数量
	uint32 mAffectedRows;

	QueryThread * qt;
};

class SERVER_DECL QueryResult
{
public:
	QueryResult(uint32 fields, uint32 rows) : mFieldCount(fields), mRowCount(rows), mCurrentRow(NULL),mDBConnection(NULL) {}
	virtual ~QueryResult() {}

	virtual bool NextRow() = 0;
	void Delete() { delete this; }

	WGSERVER_INLINE Field* Fetch() { return mCurrentRow; }
	//fetch row with feildnames
	WGSERVER_INLINE Fields * FetchRow();

	WGSERVER_INLINE uint32 GetFieldCount() const { return mFieldCount; }
	WGSERVER_INLINE uint32 GetRowCount() const { return mRowCount; }
	
	WGSERVER_INLINE  DatabaseConnection  * GetConnection(void) {	return mDBConnection;	}
	WGSERVER_INLINE  void SetConnection(DatabaseConnection  * conn)	{  mDBConnection = conn;	}
protected:
	uint32 mFieldCount;
	std::vector<String>  mFieldNames;

	uint32 mRowCount;
        Field *mCurrentRow;
        Fields  mCurrentNameRows;
	DatabaseConnection  * mDBConnection;
};

class SERVER_DECL QueryThread : public CThread
{
	friend class Database;
	Database * db;
public:
	QueryThread(Database * d) : CThread(), db(d) {}
	~QueryThread();
	bool run();
};

#endif
